import constant from "./constant";
import CryptoJS from "crypto-js";
import store from "../store";

export default {
  /**
   * 推送通知处理工具
   * @param {Array} notices - 原始通知数组
   * @param {boolean} isNotification - 标识是否是通知模式
   * @returns {Array|Object} 返回过滤后的通知数组或结构化的推送对象
   */
  pushNotification(notices, isNotification) {
    if (isNotification) {
      if (this.isEmpty(notices)) {
        return [];
      } else {
        return notices.filter(
          (f) =>
            "推送标题：" !== f.substr(0, 5) &&
            "推送封面：" !== f.substr(0, 5) &&
            "推送链接：" !== f.substr(0, 5)
        );
      }
    } else {
      let push = {};
      notices.forEach((notice) => {
        if ("推送标题：" === notice.substr(0, 5)) {
          push["标题"] = notice.substr(5);
        } else if ("推送封面：" === notice.substr(0, 5)) {
          push["封面"] = notice.substr(5);
        } else if ("推送链接：" === notice.substr(0, 5)) {
          push["链接"] = notice.substr(5);
        }
      });
      return push;
    }
  },

  /**
   * 检测移动端设备
   * @returns {boolean} 返回是否为移动端环境
   */
  mobile() {
    let flag = navigator.userAgent.match(
      /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
    );
    return flag && flag.length && flag.length > 0;
  },

  /**
   * 空值检查工具
   * @param {*} value - 需要检查的值
   * @returns {boolean} 返回是否为空值
   * @description 支持类型: undefined/null/空字符串/空数组/空对象
   * @example
   * isEmpty([]) => true
   * isEmpty({}) => true
   * isEmpty(' ') => true
   */
  isEmpty(value) {
    if (
      typeof value === "undefined" ||
      value === null ||
      (typeof value === "string" && value.trim() === "") ||
      (Array.prototype.isPrototypeOf(value) && value.length === 0) ||
      (Object.prototype.isPrototypeOf(value) && Object.keys(value).length === 0)
    ) {
      return true;
    } else {
      return false;
    }
  },

  /**
   * AES加密工具
   * @param {string} plaintText - 待加密明文
   * @returns {string} 返回Base64编码的加密结果(已进行URL安全字符替换)
   * @description 使用ECB模式/PKCS7填充，密钥来自constant配置
   */
  encrypt(plaintText) {
    let options = {
      mode: CryptoJS.mode.ECB,
      padding: CryptoJS.pad.Pkcs7,
    };
    let key = CryptoJS.enc.Utf8.parse(constant.cryptojs_key);
    let encryptedData = CryptoJS.AES.encrypt(plaintText, key, options);
    return encryptedData.toString().replace(/\//g, "_").replace(/\+/g, "-");
  },

  /**
   * AES解密工具
   * @param {string} encryptedBase64Str - Base64编码的加密字符串
   * @returns {string} 返回UTF-8格式的明文
   * @description 需要先进行URL安全字符逆向替换
   */
  decrypt(encryptedBase64Str) {
    let val = encryptedBase64Str.replace(/\-/g, "+").replace(/_/g, "/");
    let options = {
      mode: CryptoJS.mode.ECB,
      padding: CryptoJS.pad.Pkcs7,
    };
    let key = CryptoJS.enc.Utf8.parse(constant.cryptojs_key);
    let decryptedData = CryptoJS.AES.decrypt(val, key, options);
    return CryptoJS.enc.Utf8.stringify(decryptedData);
  },

  /**
   * 表情符号转换工具
   * @param {string} content - 原始内容
   * @returns {string} 返回替换表情为<img>标签后的内容
   * @description 使用正则匹配[]格式的表情标记，依赖constant.emojiList配置
   */
  faceReg(content) {
    content = content.replace(/\[[^\[^\]]+\]/g, (word) => {
      let index = constant.emojiList.indexOf(
        word.replace("[", "").replace("]", "")
      );
      if (index > -1) {
        let url =
          store.state.sysConfig["webStaticResourcePrefix"] +
          "emoji/q" +
          (index + 1) +
          ".gif";
        return (
          '<img loading="lazy" style="vertical-align: middle;width: 32px;height: 32px" src="' +
          url +
          '" title="' +
          word +
          '"/>'
        );
      } else {
        return word;
      }
    });
    return content;
  },

  /**
   * 图片标记转换工具
   * @param {string} content - 原始内容
   * @returns {string} 返回替换图片标记为<img>标签后的内容
   * @description 解析格式为[描述,URL]的图片标记，支持最大宽度250px
   */
  pictureReg(content) {
    content = content.replace(/\[[^\[^\]]+\]/g, (word) => {
      let index = word.indexOf(",");
      if (index > -1) {
        let arr = word.replace("[", "").replace("]", "").split(",");
        return (
          '<img loading="lazy" class="pictureReg" style="border-radius: 5px;width: 100%;max-width: 250px;display: block" src="' +
          arr[1] +
          '" title="' +
          arr[0] +
          '"/>'
        );
      } else {
        return word;
      }
    });
    return content;
  },

  /**
   * 图片预览功能初始化
   * @param {string} select - jQuery选择器
   * @description 实现点击图片放大预览功能，包含响应式尺寸计算和动画效果
   */
  imgShow(select) {
    $(select).click(function () {
      let src = $(this).attr("src");
      $("#bigImg").attr("src", src);

      /** 获取当前点击图片的真实大小，并显示弹出层及大图 */
      $("<img/>")
        .attr("src", src)
        .load(function () {
          let windowW = $(window).width(); //获取当前窗口宽度
          let windowH = $(window).height(); //获取当前窗口高度
          let realWidth = this.width; //获取图片真实宽度
          let realHeight = this.height; //获取图片真实高度
          let imgWidth, imgHeight;
          let scale = 0.8; //缩放尺寸，当图片真实宽度和高度大于窗口宽度和高度时进行缩放

          if (realHeight > windowH * scale) {
            //判断图片高度
            imgHeight = windowH * scale; //如大于窗口高度，图片高度进行缩放
            imgWidth = (imgHeight / realHeight) * realWidth; //等比例缩放宽度
            if (imgWidth > windowW * scale) {
              //如宽度仍大于窗口宽度
              imgWidth = windowW * scale; //再对宽度进行缩放
            }
          } else if (realWidth > windowW * scale) {
            //如图片高度合适，判断图片宽度
            imgWidth = windowW * scale; //如大于窗口宽度，图片宽度进行缩放
            imgHeight = (imgWidth / realWidth) * realHeight; //等比例缩放高度
          } else {
            //如果图片真实高度和宽度都符合要求，高宽不变
            imgWidth = realWidth;
            imgHeight = realHeight;
          }
          $("#bigImg").css("width", imgWidth); //以最终的宽度对图片缩放

          let w = (windowW - imgWidth) / 2; //计算图片与窗口左边距
          let h = (windowH - imgHeight) / 2; //计算图片与窗口上边距
          $("#innerImg").css({ top: h, left: w }); //设置top和left属性
          $("#outerImg").fadeIn("fast"); //淡入显示
        });

      $("#outerImg").click(function () {
        //再次点击淡出消失弹出层
        $(this).fadeOut("fast");
      });
    });
  },

  /**
   * 时间字符串转时间戳
   * @param {string} dateStr - 日期字符串(支持yyyy-MM-dd格式)
   * @returns {number} 返回时间戳
   */
  getDateTimeStamp(dateStr) {
    return Date.parse(dateStr.replace(/-/gi, "/"));
  },

  /**
   * 相对时间格式化工具
   * @param {string} dateStr - 日期字符串
   * @returns {string} 返回人性化的时间差描述
   * @description 支持范围：秒前 -> 3天前 -> 精确时间
   */
  getDateDiff(dateStr) {
    let publishTime = isNaN(Date.parse(dateStr.replace(/-/gi, "/")) / 1000)
      ? Date.parse(dateStr) / 1000
      : Date.parse(dateStr.replace(/-/gi, "/")) / 1000;
    let d_seconds,
      d_minutes,
      d_hours,
      d_days,
      timeNow = Math.floor(new Date().getTime() / 1000),
      d,
      date = new Date(publishTime * 1000),
      Y = date.getFullYear(),
      M = date.getMonth() + 1,
      D = date.getDate(),
      H = date.getHours(),
      m = date.getMinutes(),
      s = date.getSeconds();
    //小于10的在前面补0
    if (M < 10) {
      M = "0" + M;
    }
    if (D < 10) {
      D = "0" + D;
    }
    if (H < 10) {
      H = "0" + H;
    }
    if (m < 10) {
      m = "0" + m;
    }
    if (s < 10) {
      s = "0" + s;
    }
    d = timeNow - publishTime;
    d_days = Math.floor(d / 86400);
    d_hours = Math.floor(d / 3600);
    d_minutes = Math.floor(d / 60);
    d_seconds = Math.floor(d);
    if (d_days > 0 && d_days < 3) {
      return d_days + "天前";
    } else if (d_days <= 0 && d_hours > 0) {
      return d_hours + "小时前";
    } else if (d_hours <= 0 && d_minutes > 0) {
      return d_minutes + "分钟前";
    } else if (d_seconds < 60) {
      if (d_seconds <= 0) {
        return "刚刚发表";
      } else {
        return d_seconds + "秒前";
      }
    } else if (d_days >= 3) {
      return Y + "-" + M + "-" + D + " " + H + ":" + m;
    }
  },

  /**
   * 资源保存工具方法
   * @param {Object} that - Vue组件实例
   * @param {string} type - 资源类型
   * @param {string} path - 资源路径
   * @param {number} size - 文件大小
   * @param {string} mimeType - MIME类型
   * @param {string} originalName - 原始文件名
   * @param {string} storeType - 存储类型
   * @param {boolean} [isAdmin=false] - 是否管理员操作(可选参数)
   */
  saveResource(
    that,
    type,
    path,
    size,
    mimeType,
    originalName,
    storeType,
    isAdmin = false
  ) {
    let resource = {
      type: type,
      path: path,
      size: size,
      mimeType: mimeType,
      storeType: storeType,
      originalName: originalName,
    };

    that.$http
      .post(
        that.$constant.baseURL + "/resource/saveResource",
        resource,
        isAdmin
      )
      .catch((error) => {
        that.$message({
          message: error.message,
          type: "error",
        });
      });
  },

  /**
   * 时间差计算工具
   * @param {string} oldTime - 开始时间
   * @param {string|Date} [newTime] - 结束时间(可选，默认当前时间)
   * @returns {Object} 返回包含年月日时分秒差值的对象
   * @see https://juejin.cn/post/7153816601156911118 算法来源
   */
  timeDiff(oldTime, newTime) {
    oldTime = oldTime.replace(new RegExp("-", "gm"), "/");
    if (newTime) {
      newTime = newTime.replace(new RegExp("-", "gm"), "/");
    } else {
      newTime = new Date();
    }

    // 计算比较日期
    const getMaxMinDate = (time, twoTime, type) => {
      let minTime =
        new Date(time).getTime() - new Date(twoTime).getTime() > 0
          ? twoTime
          : time;
      let maxTime =
        new Date(time).getTime() - new Date(twoTime).getTime() > 0
          ? time
          : twoTime;
      let maxDateDay = new Date(
        new Date(maxTime).getFullYear(),
        new Date(maxTime).getMonth() + 1,
        0
      ).getDate();
      let maxMinDate =
        new Date(minTime).getDate() > maxDateDay
          ? maxDateDay
          : new Date(minTime).getDate();
      let maxMinTong;
      if (type === "month") {
        maxMinTong =
          new Date(maxTime).getFullYear() +
          "/" +
          (new Date(minTime).getMonth() + 1) +
          "/" +
          maxMinDate +
          " " +
          new Date(minTime).toLocaleTimeString("chinese", { hour12: false });
      } else {
        maxMinTong =
          new Date(maxTime).getFullYear() +
          "/" +
          (new Date(maxTime).getMonth() + 1) +
          "/" +
          maxMinDate +
          " " +
          new Date(minTime).toLocaleTimeString("chinese", { hour12: false });
      }
      return {
        minTime,
        maxTime,
        maxMinTong,
      };
    };

    // 相差年份
    const getYear = (time, twoTime) => {
      let oneYear = new Date(time).getFullYear();
      let twoYear = new Date(twoTime).getFullYear();
      const { minTime, maxTime, maxMinTong } = getMaxMinDate(
        time,
        twoTime,
        "month"
      );
      let chaYear = Math.abs(oneYear - twoYear);
      if (new Date(maxMinTong).getTime() > new Date(maxTime).getTime()) {
        chaYear--;
      }
      return chaYear;
    };

    // 相差月份
    const getMonth = (time, twoTime, value) => {
      let oneMonth =
        new Date(time).getFullYear() * 12 + (new Date(time).getMonth() + 1);
      let twoMonth =
        new Date(twoTime).getFullYear() * 12 +
        (new Date(twoTime).getMonth() + 1);
      const { minTime, maxTime, maxMinTong } = getMaxMinDate(
        time,
        twoTime,
        "day"
      );
      let chaMonth = Math.abs(oneMonth - twoMonth);
      if (new Date(maxMinTong).getTime() > new Date(maxTime).getTime()) {
        chaMonth--;
      }
      if (value) {
        return chaMonth - value;
      } else {
        return chaMonth;
      }
    };

    // 相差天数
    const getDay = (time, twoTime, value) => {
      let chaTime = Math.abs(
        new Date(time).getTime() - new Date(twoTime).getTime()
      );
      if (value) {
        return parseInt(chaTime / 86400000) - value;
      } else {
        return parseInt(chaTime / 86400000);
      }
    };

    // 相差小时
    const getHour = (time, twoTime, value) => {
      let chaTime = Math.abs(
        new Date(time).getTime() - new Date(twoTime).getTime()
      );
      if (value) {
        return parseInt(chaTime / 3600000) - value;
      } else {
        return parseInt(chaTime / 3600000);
      }
    };

    // 相差分钟
    const getMinute = (time, twoTime, value) => {
      let chaTime = Math.abs(
        new Date(time).getTime() - new Date(twoTime).getTime()
      );
      if (value) {
        return parseInt(chaTime / 60000) - value;
      } else {
        return parseInt(chaTime / 60000);
      }
    };

    // 相差秒
    const getSecond = (time, twoTime, value) => {
      let chaTime = Math.abs(
        new Date(time).getTime() - new Date(twoTime).getTime()
      );
      if (value) {
        return parseInt(chaTime / 1000) - value;
      } else {
        return parseInt(chaTime / 1000);
      }
    };

    // 相差年月日时分秒
    const getDiffYMDHMS = (time, twoTime) => {
      const { minTime, maxTime, maxMinTong } = getMaxMinDate(
        time,
        twoTime,
        "day"
      );
      let diffDay1 = getDay(minTime, maxMinTong);
      if (new Date(maxMinTong).getTime() > new Date(maxTime).getTime()) {
        let prevMonth = new Date(maxMinTong).getMonth() - 1;
        let lastTime = new Date(maxMinTong).setMonth(prevMonth);
        diffDay1 =
          diffDay1 -
          getDay(
            new Date(lastTime).getFullYear() +
              "/" +
              (new Date(lastTime).getMonth() + 1) +
              "/" +
              new Date(lastTime).getDate(),
            maxMinTong
          );
      }
      let diffYear = getYear(time, twoTime);
      let diffMonth = getMonth(time, twoTime, diffYear * 12);
      let diffDay = getDay(time, twoTime, diffDay1);
      let diffHour = getHour(time, twoTime, getDay(time, twoTime) * 24);
      let diffMinute = getMinute(
        time,
        twoTime,
        getDay(time, twoTime) * 24 * 60 + diffHour * 60
      );
      let diffSecond = getSecond(
        time,
        twoTime,
        getDay(time, twoTime) * 24 * 60 * 60 +
          diffHour * 60 * 60 +
          diffMinute * 60
      );
      return {
        diffYear,
        diffMonth,
        diffDay,
        diffHour,
        diffMinute,
        diffSecond,
      };
    };

    return getDiffYMDHMS(oldTime, newTime);
  },

  /**
   * 倒计时计算工具
   * @param {string} time - 目标时间字符串
   * @returns {Object} 返回包含天/时/分/秒的倒计时对象
   */
  countdown(time) {
    time = new Date(time.replace(new RegExp("-", "gm"), "/"));
    let nowTime = new Date();
    //两个时间点的时间差(秒)
    let seconds = parseInt((time.getTime() - nowTime.getTime()) / 1000);
    let d = parseInt(seconds / 3600 / 24);
    let h = parseInt((seconds / 3600) % 24);
    let m = parseInt((seconds / 60) % 60);
    let s = parseInt(seconds % 60);
    return {
      d,
      h,
      m,
      s,
    };
  },
  /**
   * 日期格式化工具函数
   * @param {Date|number|string} date - 可接收Date对象、时间戳或日期字符串
   * @param {string} formatStr - 格式字符串，默认 'yyyy-MM-dd HH:mm:ss'
   * @returns {string} 格式化后的日期字符串
   */
  formatDate(date, formatStr = "yyyy-MM-dd HH:mm:ss") {
    // 处理传入的日期参数
    const d = new Date(date);
    if (isNaN(d.getTime())) throw new Error("Invalid date parameter");

    // 定义格式映射（包含12/24小时制处理）
    const map = {
      "y+": d.getFullYear(), // 年份
      "M+": d.getMonth() + 1, // 月份（0-11需要+1）
      "d+": d.getDate(), // 日期
      "H+": d.getHours(), // 24小时制
      "h+": d.getHours() % 12 || 12, // 12小时制
      "m+": d.getMinutes(), // 分钟
      "s+": d.getSeconds(), // 秒
      "q+": Math.floor((d.getMonth() + 3) / 3), // 季度
      S: d.getMilliseconds(), // 毫秒
    };

    // 特殊处理年份（支持yy短格式）
    if (/(y+)/.test(formatStr)) {
      formatStr = formatStr.replace(
        RegExp.$1,
        ("" + map["y+"]).substr(4 - RegExp.$1.length)
      );
    }

    // 遍历替换其他格式符
    for (const [key, value] of Object.entries(map)) {
      const regex = new RegExp(`(${key})`);
      if (regex.test(formatStr)) {
        // 处理补零和特殊格式
        const str =
          RegExp.$1.length === 1 ? value : String(value).padStart(2, "0");
        formatStr = formatStr.replace(regex, str);
      }
    }

    return formatStr;
  },
};
